package com.yiren.dbaa.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.LinkedList;
import java.util.List;

public class GYROPointView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private SurfaceHolder holder;
    private Paint paintGrid;
    private Paint paintLine;
    private Paint paintPoint1;
    private Paint paintPoint2;

    private int width, height;
    private float scale;
    private boolean drawGrid;
    private boolean drawLine;
    private boolean running;

    private List<Float> xPoints1;
    private List<Float> yPoints1;
    private int maxPoint1;

    private List<Float> xPoints2;
    private List<Float> yPoints2;
    private int maxPoint2;
    private boolean showPoint2;

    private float[] maxX;
    private float[] minX;
    private float[] maxY;
    private float[] minY;

    public GYROPointView(Context context) {
        this(context, null);
    }

    public GYROPointView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GYROPointView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        paintGrid = new Paint();
        paintGrid.setStyle(Paint.Style.FILL);
        paintGrid.setColor(0xFFAAAAAA);
        paintGrid.setStrokeWidth(1);
        paintGrid.setPathEffect(new DashPathEffect(new float[]{8, 8}, 0));

        paintLine = new Paint();
        paintLine.setStyle(Paint.Style.FILL);
        paintLine.setAntiAlias(true);
        paintLine.setColor(0xFF33CCCC);
        paintLine.setStrokeWidth(2);

        paintPoint1 = new Paint();
        paintPoint1.setStyle(Paint.Style.FILL);
        paintPoint1.setAntiAlias(true);
        paintPoint1.setColor(0xFF33CC33);

        paintPoint2 = new Paint();
        paintPoint2.setStyle(Paint.Style.FILL);
        paintPoint2.setAntiAlias(true);
        paintPoint2.setColor(0xFF3333CC);

        scale = 1;
        drawGrid = false;
        drawLine = false;
        running = false;

        maxPoint1 = -1;
        xPoints1 = new LinkedList<>();
        yPoints1 = new LinkedList<>();

        maxPoint2 = -1;
        xPoints2 = new LinkedList<>();
        yPoints2 = new LinkedList<>();

        maxX = new float[6];
        minX = new float[6];
        maxY = new float[6];
        minY = new float[6];
        for (int i = 0; i < 6; i++) {
            maxX[i] = minX[i] = maxY[i] = minY[i] = 0;
        }

        getHolder().addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        this.holder = holder;
        (new Thread(this)).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        this.width = width;
        this.height = height;

        int len = Math.min(width, height);
        scale = len / 60.0f;
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        running = false;
    }

    @Override
    public void run() {
        System.out.println("GYROPointView start.");
        running = true;

        while (running) {
            try {
                if (holder != null) {
                    Canvas canvas = holder.lockCanvas();
                    canvas.drawColor(0xFFFFFFFF);
                    drawGrid(canvas);
                    drawLine(canvas);
                    drawPoints1(canvas);
                    drawPoints2(canvas);
                    drawMaxMin(canvas);
                    holder.unlockCanvasAndPost(canvas);
                }
                Thread.sleep(60);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        running = false;
        System.out.println("GYROPointView finish.");
    }

    private void drawGrid(Canvas canvas) {
        if (drawGrid) {
            for (int i = 0; i * 10 <= 30; i++) {
                float g = toPixel(i * 10);
                canvas.drawLine(0, height / 2.0f - g, width, height / 2.0f - g, paintGrid);
                canvas.drawLine(0, height / 2.0f + g, width, height / 2.0f + g, paintGrid);
                canvas.drawLine(width / 2.0f - g, 0, width / 2.0f - g, height, paintGrid);
                canvas.drawLine(width / 2.0f + g, 0, width / 2.0f + g, height, paintGrid);
            }
        }
    }

    private synchronized void drawLine(Canvas canvas) {
        if (drawLine) {
            for (int i = 1; i < xPoints1.size() && drawLine; i++) {
                float x1 = xPoints1.get(i - 1);
                float y1 = yPoints1.get(i - 1);
                float x2 = xPoints1.get(i);
                float y2 = yPoints1.get(i);
                canvas.drawLine(width / 2.0f + toPixel(x1), height / 2.0f - toPixel(y1), width / 2.0f + toPixel(x2), height / 2.0f - toPixel(y2), paintLine);
            }
        }
    }

    private synchronized void drawPoints1(Canvas canvas) {
        for (int i = 0; i < xPoints1.size(); i++) {
            float x = xPoints1.get(i);
            float y = yPoints1.get(i);
            canvas.drawCircle(width / 2.0f + toPixel(x), height / 2.0f - toPixel(y), 4, paintPoint1);
        }
    }

    private synchronized void drawPoints2(Canvas canvas) {
        if (showPoint2) {
            for (int i = 0; i < xPoints2.size(); i++) {
                float x = xPoints2.get(i);
                float y = yPoints2.get(i);
                canvas.drawCircle(width / 2.0f + toPixel(x), height / 2.0f - toPixel(y), 4, paintPoint2);
            }
        }
    }

    private synchronized void drawMaxMin(Canvas canvas) {
        for (int i = 0; i < 6; i++) {
            if (maxX[i] > minX[i] && maxY[i] > minY[i]) {
                canvas.drawLine(width / 2.0f + toPixel(minX[i]), height / 2.0f - toPixel(maxY[i]), width / 2.0f + toPixel(maxX[i]), height / 2.0f - toPixel(maxY[i]), paintLine);
                canvas.drawLine(width / 2.0f + toPixel(maxX[i]), height / 2.0f - toPixel(maxY[i]), width / 2.0f + toPixel(maxX[i]), height / 2.0f - toPixel(minY[i]), paintLine);
                canvas.drawLine(width / 2.0f + toPixel(maxX[i]), height / 2.0f - toPixel(minY[i]), width / 2.0f + toPixel(minX[i]), height / 2.0f - toPixel(minY[i]), paintLine);
                canvas.drawLine(width / 2.0f + toPixel(minX[i]), height / 2.0f - toPixel(minY[i]), width / 2.0f + toPixel(minX[i]), height / 2.0f - toPixel(maxY[i]), paintLine);
            }
        }
    }

    public void setDrawLine(boolean drawLine) {
        this.drawLine = drawLine;
    }

    public void setDrawGrid(boolean drawGrid) {
        this.drawGrid = drawGrid;
    }

    public void setMaxPoint1(int maxPoint) {
        this.maxPoint1 = maxPoint;
    }

    public void setMaxPoint2(int maxPoint) {
        this.maxPoint2 = maxPoint;
    }

    public void setShowPoint2(boolean showPoint2) {
        this.showPoint2 = showPoint2;
    }

    public void setMaxMin(int index, float maxX, float minX, float maxY, float minY) {
        if (0 <= index && index < 6) {
            this.maxX[index] = maxX;
            this.minX[index] = minX;
            this.maxY[index] = maxY;
            this.minY[index] = minY;
        }
    }

    public synchronized void addPoint1(float x, float y) {
        xPoints1.add(x);
        yPoints1.add(y);
        if (maxPoint1 > 0 && xPoints1.size() > maxPoint1) {
            xPoints1.remove(0);
        }
        if (maxPoint1 > 0 && yPoints1.size() > maxPoint1) {
            yPoints1.remove(0);
        }
    }

    public synchronized void addPoint2(float x, float y) {
        xPoints2.add(x);
        yPoints2.add(y);
        if (maxPoint2 > 0 && xPoints2.size() > maxPoint2) {
            xPoints2.remove(0);
        }
        if (maxPoint2 > 0 && yPoints2.size() > maxPoint2) {
            yPoints2.remove(0);
        }
    }

    public void clearLocations() {
        xPoints1.clear();
        yPoints1.clear();
        xPoints2.clear();
        yPoints2.clear();
    }

    private int toPixel(float degree) {
        return (int) (degree * scale);
    }

}
